'''
Date: 2025-08-20 17:25:46
Description: 聊天页获取个人信息
FilePath: \openCV\get_message_person_info.py
'''

import re, uiautomation as auto
import sys
import sex_model
from PIL import ImageGrab
from PIL import Image

TITLE_PATTERNS = [r'.*BOSS直聘.*']            # 标题模糊匹配
CHROME_CLASSES = {'Chrome_WidgetWin_0', 'Chrome_WidgetWin_1'}
MAX_DEPTH = 100
SEARCH_TMO = 3.0
PER_ITEM_TMO = 3.0

def list_top_windows():
    root = auto.GetRootControl()
    rows = []
    for w in root.GetChildren():
        try:
            rows.append((w.ControlTypeName, w.Name or '', w.ClassName or '', w))
        except Exception:
            pass
    for i, (t, n, c, _) in enumerate(rows, 1):
        print(f"{i:02d}. type={t:14} name='{n}' class='{c}'",file=sys.stderr)
    return rows
def name_matches(name: str) -> bool:
    return any(re.fullmatch(pat, name or '') for pat in TITLE_PATTERNS)


def get_boss_window(timeout: float = 3.0):
    """
    获取 BOSS直聘 根控件（WindowControl 或 PaneControl）
    :param timeout: 查找超时，秒
    :return: Control 对象或 None
    """
    with auto.UIAutomationInitializerInThread():
        auto.SetGlobalSearchTimeout(0.5)
        # 1) 先尝试 WindowControl（标准顶层窗口）
        win = auto.WindowControl(RegexName=r'.*BOSS直聘.*', searchDepth=1)
        if win.Exists(timeout, 0.2):
            return win
        # 2) 回退：在顶层 PaneControl 里找（Electron/Chromium 应用常见）
        root = auto.GetRootControl()
        for c in root.GetChildren():
            if 'BOSS直聘' in (c.Name or '') and c.ClassName in ('Chrome_WidgetWin_0', 'Chrome_WidgetWin_1'):
                return c
    print("❌ 未找到 BOSS直聘 窗口",file=sys.stderr)
    return None

def pick_boss_root():
    """返回最合理的 BOSS 根节点（Window 或 Pane）"""
    # 1) 先尝试 WindowControl（如果 BOSS 是真正的顶层窗口）
    for pat in TITLE_PATTERNS:
        win = auto.WindowControl(RegexName=pat, searchDepth=1)
        if win.Exists(SEARCH_TMO, 0.2):
            return win
    # 2) 回退：在顶层子控件中找 PaneControl + Class=Chrome_WidgetWin_* + Name 匹配
    tops = list_top_windows()  # 也顺便打印出来方便你核对
    candidates = []
    for _, name, cls, elem in tops:
        if cls in CHROME_CLASSES and name_matches(name):
            candidates.append(elem)
    if candidates:
        # 取面积最大者作为根
        def area(e):
            try:
                r = e.BoundingRectangle
                return max(0, (r.right - r.left)) * max(0, (r.bottom - r.top))
            except Exception:
                return -1
        return max(candidates, key=area)
    return None

def get_all_texts(root_ctrl, max_depth=None):
    """
    遍历 root_ctrl 下的所有子孙，收集 Text/Document 控件的 Name
    """
    texts = []
    def walk(ctrl, depth=0):
        if max_depth is not None and depth > max_depth:
            return
        try:
            children = ctrl.GetChildren()
        except Exception:
            return
        for c in children:
            try:
                if c.ControlTypeName in ('TextControl', 'GroupControl'):
                    if c.Name:  # 去掉空
                        texts.append(c.Name.strip())
            except Exception:
                pass
            walk(c, depth+1)
    walk(root_ctrl)
    return texts
try:
    import mss
except Exception:
    mss = None

# --------- 直接从 UIAutomation 获取两个 TextControl 的 rect ---------
def BR(ctrl):
    """安全取控件矩形 (L,T,R,B)"""
    try:
        rect = ctrl.BoundingRectangle
        return (rect.left, rect.top, rect.right, rect.bottom)
    except Exception:
        return (0, 0, 0, 0)

def iter_all_children(ctrl, max_depth=6):
    """递归遍历所有子孙控件（兼容所有版本）"""
    results = []
    def _walk(c, depth=0):
        if depth > max_depth:
            return
        try:
            children = c.GetChildren()
        except Exception:
            return
        for x in children:
            results.append(x)
            _walk(x, depth + 1)
    _walk(ctrl, 0)
    return results

def crop_icon_between_rects(lrect, rrect, out_path):
    """从左右矩形间截取图像"""
    top = min(lrect[1], rrect[1])
    bottom = max(lrect[3], rrect[3])
    left = lrect[2]
    right = rrect[0]
    if right - left < 2:
        print(f"gap过小 ({right-left}px)，跳过截图", file=sys.stderr)
        return None

    img = ImageGrab.grab(bbox=(left, top, right, bottom))
    img.save(out_path)
    # print(f"已保存截图: {out_path}", file=sys.stderr)
    return out_path

def crop_icon_by_names(win,out_path='gender_icon.png'):
    with auto.UIAutomationInitializerInThread():
        # 找窗口（顶层或 Electron Pane）
        auto.SetGlobalSearchTimeout(0.5)
        #win = auto.WindowControl(RegexName=r'.*BOSS直聘.*', searchDepth=1)
        if not win.Exists(2, 0.2):
            # 兜底：从根下找 pane
            root = auto.GetRootControl()
            for c in root.GetChildren():
                if 'BOSS直聘' in (c.Name or '') and c.ClassName in ('Chrome_WidgetWin_0', 'Chrome_WidgetWin_1'):
                    win = c; break
        if not win:
            raise RuntimeError('未找到 BOSS直聘 窗口')

        onlineResumeBtn = auto.HyperlinkControl(searchFromControl=win, Name='在线简历')

        left_ctrl = onlineResumeBtn.GetParentControl().GetFirstChildControl().GetFirstChildControl().GetFirstChildControl()
        right_ctrl = onlineResumeBtn.GetParentControl().GetFirstChildControl().GetLastChildControl()

        if not left_ctrl.Exists(2, 0.2):
            raise RuntimeError(f'未找到姓名文本')
        if not right_ctrl.Exists(2, 0.2):
            raise RuntimeError(f'未找到右侧文本')

        lrect = BR(left_ctrl)
        rrect = BR(right_ctrl)

        return crop_icon_between_rects(lrect, rrect, out_path=out_path)


'''
性别： 男
基础信息: ['21岁', '3年', '大专']
名字： ['王某', '刚刚活跃']
职位-期望 ['沟通职位：', '品类运营', '期望：', '', '淮北 · 销售专员', '5-6K']
'''
def execute(win):
    with auto.UIAutomationInitializerInThread():
        if win == None:
            win = get_boss_window()
        #win = get_boss_window()  # pick_boss_root()
        win.Exists(3, 0.2)  # 超时等待
        onlineResumeBtn = auto.HyperlinkControl(searchFromControl=win, Name='在线简历')


        # 获取性别
        crop_icon_by_names(win,out_path='gender_icon.png')
        image = Image.open('gender_icon.png').convert('RGB')
        icon = sex_model.extract_icon(image)
        gender = sex_model.sex_main('assets/icon_gender_model.pth', icon)
        if gender['prediction'] == 'female_icon':
            gender = '女'
        elif gender['prediction'] == 'male_icon':
            gender = '男'
        else:
            gender = '未知'
        # print('性别：', gender,file=sys.stderr)


        baseInfo = onlineResumeBtn.GetPreviousSiblingControl()
        baseInfoText = get_all_texts(baseInfo)
        # print('基础信息:',baseInfoText,file=sys.stderr)

        name = baseInfo.GetPreviousSiblingControl()
        nameText = get_all_texts(name)
        # print('名字：',nameText,file=sys.stderr)

        post_expectation = onlineResumeBtn.GetNextSiblingControl().GetNextSiblingControl().GetChildren()[1]
        post_expectationText = get_all_texts(post_expectation)
        # print('职位-期望',post_expectationText,file=sys.stderr)

        # 初始化教育信息默认值
        education = "未知"

        # 检查列表长度是否足够，避免越界
        if len(baseInfoText) >= 3:
            education = baseInfoText[2]
        else:
            # 可根据实际需求添加日志提示
            print("基础信息列表长度不足，无法获取教育信息", file=sys.stderr)

        name_text0 = nameText[0] if len(nameText) > 0 else ''
        name_state = nameText[1] if len(nameText) > 1 else ''
        age = baseInfoText[0] if len(baseInfoText) > 0 else ''
        wordExperience = baseInfoText[1] if len(baseInfoText) > 1 else ''
        education = baseInfoText[2] if len(baseInfoText) > 2 else '未知'
        post = post_expectationText[1] if len(post_expectationText) > 1 else ''
        expectationPost = post_expectationText[4] if len(post_expectationText) > 4 else ''
        expectationSalary = post_expectationText[5] if len(post_expectationText) > 5 else ''

        result = {
            "gender": gender,
            "name": name_text0,
            "state": name_state,
            "age": age,
            "wordExperience": wordExperience,
            "education": education,
            "post": post,
            "expectationPost": expectationPost,
            "expectationSalary": expectationSalary
        }
        return result

# print('开始执行')
# results = execute(None)
# print(results)